﻿//Made by JK

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;


namespace LevelLibrary
{
    public class Level
    {
        public struct LevelParts
        {
            public static string CROSS = @"CINEMA4D/cross";
            public static string WALL = @"CINEMA4D/wall";
            public static string CORNER = @"CINEMA4D/corner";
            public static string TRICONN = @"CINEMA4D/triconn";
        }
        public int[,] Values { get; set; }
        private List<Model> models = new List<Model>();
        private List<Matrix> world = new List<Matrix>();

        public Level(int[,] values)
        {
            Values = values;
        }

        public int GetValue(int row, int column)
        {
            return Values[row, column];
        }

        public int Rows
        {
            get
            {
                return Values.GetLength(0);
            }
        }

        public int Columns
        {
            get
            {
                return Values.GetLength(1);
            }
        }

        public void GenerateLevel(ContentManager Content, GraphicsDeviceManager graphics )        
        {
            Global.Vision.view = Matrix.CreateLookAt(new Vector3(Columns, 12, Rows), new Vector3(Columns / 2, -3, Rows / 2), Vector3.UnitY);
            Global.Vision.projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(80), graphics.PreferredBackBufferWidth / graphics.PreferredBackBufferHeight, 0.1f, 100f);
            for (int row = 0; row < Rows; row++)
            {
                for (int column = 0; column < Columns; column++)
                {
                    if ((Values[row, column] & 1) == 1)    //jeżeli są ściany
                    {
                        switch (Values[row, column] & (0x0F << 8))
                        {
                            case 0x000:                                              //cross
                            case 0xF00:
                                models.Add(Content.Load<Model>(LevelParts.CROSS));
                                world.Add(Matrix.CreateTranslation(new Vector3(column, 0.5f, row)));
                                break;
                            case 0x100:
                            case 0x200:
                            case 0x300:                                             //wall horizontal
                                models.Add(Content.Load<Model>(LevelParts.WALL));
                                world.Add(Matrix.CreateRotationY(MathHelper.ToRadians(90)) * Matrix.CreateTranslation(new Vector3(column, 0.5f, row)));
                                break;
                            case 0x400:
                            case 0x800:
                            case 0xC00:                                             //wall vertical
                                models.Add(Content.Load<Model>(LevelParts.WALL));
                                world.Add(Matrix.CreateTranslation(new Vector3(column, 0.5f, row)));
                                break;
                            case 0x900:                                             //corner left-bottom
                                models.Add(Content.Load<Model>(LevelParts.CORNER));
                                world.Add(Matrix.CreateTranslation(new Vector3(column, 0.5f, row)));
                                break;
                            case 0x500:                                              //corner left-upper
                                models.Add(Content.Load<Model>(LevelParts.CORNER));
                                world.Add(Matrix.CreateRotationY(MathHelper.ToRadians(270)) * Matrix.CreateTranslation(new Vector3(column, 0.5f, row)));
                                break;
                            case 0x600:                                             //corner right-upper
                                models.Add(Content.Load<Model>(LevelParts.CORNER));
                                world.Add(Matrix.CreateRotationY(MathHelper.ToRadians(180)) * Matrix.CreateTranslation(new Vector3(column, 0.5f, row)));
                                break;
                            case 0xA00:                                             //corner right-bottom
                                models.Add(Content.Load<Model>(LevelParts.CORNER));
                                world.Add(Matrix.CreateRotationY(MathHelper.ToRadians(90)) * Matrix.CreateTranslation(new Vector3(column, 0.5f, row)));
                                break;
                            case 0xD00:                                             //triconn right
                                models.Add(Content.Load<Model>(LevelParts.TRICONN));
                                world.Add(Matrix.CreateTranslation(new Vector3(column, 0.5f, row)));
                                break;
                            case 0x700:                                             //triconn down
                                models.Add(Content.Load<Model>(LevelParts.TRICONN));
                                world.Add(Matrix.CreateRotationY(MathHelper.ToRadians(270)) * Matrix.CreateTranslation(new Vector3(column, 0.5f, row)));
                                break;
                            case 0xE00:                                            //triconn left
                                models.Add(Content.Load<Model>(LevelParts.TRICONN));
                                world.Add(Matrix.CreateRotationY(MathHelper.ToRadians(180)) * Matrix.CreateTranslation(new Vector3(column, 0.5f, row)));
                                break;
                            case 0xB00:                                             //triconn up
                                models.Add(Content.Load<Model>(LevelParts.TRICONN));
                                world.Add(Matrix.CreateRotationY(MathHelper.ToRadians(90)) * Matrix.CreateTranslation(new Vector3(column, 0.5f, row)));
                                break;
                        }
                    }
                }
            }
        }

        public void Draw()
        {
            int i = 0;
            foreach (Model model in models)
            {

                foreach (ModelMesh mesh in model.Meshes)
                {
                    foreach (BasicEffect effect in mesh.Effects)
                    {
                        effect.World = world[i++];
                        effect.View = Global.Vision.view;
                        effect.Projection = Global.Vision.projection;
                        effect.EnableDefaultLighting();
                    }

                    mesh.Draw();
                }
            }
        }

        public Vector3 GetPlayerBornPosition()
        {
            for (int row = 0; row < Rows; row++)
            {
                for (int column = 0; column < Columns; column++)
                {
                    if ((Values[row, column] & 8) != 0)
                    {
                                               
                        return new Vector3(column,0.5f,row);
                    }
                }
            }
            return new Vector3(0, 1000, 0);
        }

        public List<Vector3> GetGhostsBornPositions()
        {
            List<Vector3> list = new List<Vector3>();

            for (int row = 0; row < Rows; row++)
            {
                for (int column = 0; column < Columns; column++)
                {
                    if ((Values[row, column] & 16) != 0)
                    {
                        list.Add(new Vector3(column, 0.5f, row));
                    }
                }
            }
            return list;
        }

        public List<Vector3> GetSmallBallsPosition()
        {
            List<Vector3> list = new List<Vector3>();

            for (int row = 0; row < Rows; row++)
            {
                for (int column = 0; column < Columns; column++)
                {
                    if ((Values[row, column] & 2) != 0)
                    {
                        list.Add(new Vector3(column, 0.5f, row));
                    }
                }
            }
            return list;
        }

        public List<Vector3> GetBigBallsPosition()
        {
            List<Vector3> list = new List<Vector3>();

            for (int row = 0; row < Rows; row++)
            {
                for (int column = 0; column < Columns; column++)
                {
                    if ((Values[row, column] & 4) != 0)
                    {
                        list.Add(new Vector3(column, 0.5f, row));
                    }
                }
            }
            return list;
        }

        public bool IsCollision(Model model,Matrix modelWorld, Vector3 wallPosition)
        {
            foreach (ModelMesh mesh in model.Meshes)
            {
                BoundingSphere sphere1 = mesh.BoundingSphere;
                sphere1 = sphere1.Transform(modelWorld);
                foreach (ModelMesh mesh2 in models[Convert.ToInt32(wallPosition.X) + Convert.ToInt32(wallPosition.Y) * Columns].Meshes)
                {
                    BoundingSphere sphere2 = mesh2.BoundingSphere;
                    sphere2 = sphere2.Transform(world[Convert.ToInt32(wallPosition.X) + Convert.ToInt32(wallPosition.Y) * Columns]);
                    if (sphere1.Intersects(sphere2))
                        return true;
                }
            }
            return false;
        }
    }
}
/*
 *   Generating levels:
 *   When generating levels, different bits define different places
 *  |...|U |D|L|R|x|x|x|g|p|b|s|w|
 *      11 10 9 8 7 6 5 4 3 2 1 0
 *  
 *  Bit 0 (w) - defines a wall  
 *  Bit 1 (s) - small ball
 *  Bit 2 (b) - big ball
 *  Bit 3 (p) - place, where pacman is born
 *  Bit 4 (g) - places, where ghosts are being born, defines also number of ghosts
 *  Bits 5-7  - for future use
 *  Bits 8-11 - reserved for level processing tools
 *  Bits 12-31- for future use
 */